package org.rsbot.injector.adapters;

import org.rsbot.client.Model;
import org.rsbot.client.ModelCapture;
import org.rsbot.injector.data.ClassData;
import org.rsbot.injector.data.FieldData;
import org.rsbot.injector.data.ModelData;
import org.rsbot.loader.asm.ClassAdapter;
import org.rsbot.loader.asm.ClassVisitor;
import org.rsbot.loader.asm.FieldVisitor;
import org.rsbot.loader.asm.MethodAdapter;
import org.rsbot.loader.asm.MethodVisitor;
import org.rsbot.loader.asm.Opcodes;
import org.rsbot.loader.asm.Type;

import java.util.logging.Logger;

/**
 *
 * @author Nader Sleiman
 */
public class ClassHackAdapter extends ClassAdapter implements Opcodes {

    private String super_class;
    private ClassData cd;

    public ClassHackAdapter(ClassVisitor cv, ClassData cd) {
        super(cv);
        this.cd = cd;
    }

    //hacks the <init> method to replace the name of the soriginal uperclass with new one.
    class HackInitAdapter extends MethodAdapter {

        public HackInitAdapter(MethodVisitor mv) {
            super(mv);
        }

        @Override
        public void visitMethodInsn(int opcode, String parent, String name, String desc) {
            if (opcode == INVOKESPECIAL && parent.equals(super_class)) {
                parent = cd.super_class;
            }
            mv.visitMethodInsn(opcode, parent, name, desc);

        }
    }

    // this is necessary for superclass overriding.
    @Override
    public MethodVisitor visitMethod(
            final int access,
            final String name,
            final String desc,
            final String signature,
            final String[] exceptions) {
        final MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
        return name.equals("<init>") ? new HackInitAdapter(mv) : mv;

    }

    @Override
    public void visit(int i, int i1, String name, String string1, String parent, String[] interfaces) {
        //caches original name to modify later in the <init> method ;).
        cd.super_class = cd.super_class == null ? parent : cd.super_class;
        super_class = cd.super_class;

        //implement additional interfaces
        for (String inter : interfaces) {
            if (!cd.interfaces.contains(inter)) {
                cd.interfaces.add(inter);
            }
        }
        cv.visit(i, i1, name, string1, cd.super_class, cd.interfaces.toArray(new String[0]));

    }
    //Inject Fields through visitEnd, to inject once.

    @Override
    public void visitEnd() {
        for (FieldData fd : cd.fields) {
            final FieldVisitor fv = cv.visitField(fd.access, fd.name, fd.desc, null, null);
            if (fv != null) {
                fv.visitEnd();
            }
        }
        cv.visitEnd();
    }
}
